#include "lvgl_app/lvgl_pm/pm_anima.h"
#include "lvgl_app/lvgl_pm/lvgl_pm.h"

#include <stdlib.h>


/*
appear    是open时 界面进入时使用  或者  back界面进入时使用
disAppear 是open时 界面退出时使用  或者  back界面退出时使用
*/

/* 所有动画end为显示或者取消显示状态 */
static lv_anim_t appear_anima;
static lv_anim_t disAppear_anima;


/* 声明两个定时器 由于异步操作 页面被关闭 回调 */
static lv_timer_t* lvgl_appear_timer = NULL;
static lv_timer_t* lvgl_disAppear_timer = NULL;

void lvgl_pm_anima_init(void)
{
    /* 直接创建两个定时器 防止频繁malloc */
    lvgl_appear_timer = lv_timer_create(NULL, 0, NULL);
    lv_timer_pause(lvgl_appear_timer);/*直接挂起定时器*/
    lvgl_disAppear_timer = lv_timer_create(NULL, 0, NULL);
    lv_timer_pause(lvgl_disAppear_timer);/*直接挂起定时器*/

}
typedef struct _lv_pm_anima_data {
    lv_pm_page_t* pm_page;
    lv_pm_anima_complete_cb cb;
    lv_pm_open_options_t options;
} lv_pm_anima_data;



static void translateX_anima_cb(void* var, int32_t v)
{
    lv_obj_set_x(var, v);
}

static void translateY_anima_cb(void* var, int32_t v)
{
    lv_obj_set_y(var, v);
}

/* 如果界面切换过快， 此回调也无法进入 因此该部分的可能无法使用user_data作为参数了 */
static void anima_ready_cb(lv_anim_t* anim)
{
    lv_pm_anima_data* cb_data = (lv_pm_anima_data*)anim->user_data;
    cb_data->cb(cb_data->pm_page, cb_data->options);
}

/**
----------------------------------------------------------------------------------------------------------
  slide animation
----------------------------------------------------------------------------------------------------------
*/

static void _pm_slide_appear(lv_pm_anima_data* anima_data)
{

    int32_t start_ops = 0;
    int32_t end_ops = 0;
    lv_anim_exec_xcb_t anima_cb = NULL;

    switch (anima_data->options.direction)
    {
    case LV_PM_ANIMA_TOP:
    {
        start_ops = lv_disp_get_ver_res(NULL);
        end_ops = 0;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_BOTTOM:
    {
        start_ops = -lv_disp_get_ver_res(NULL);
        end_ops = 0;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_RIGHT:
    {
        start_ops = lv_disp_get_hor_res(NULL);
        end_ops = 0;
        anima_cb = translateX_anima_cb;
    }
    break;
    case LV_PM_ANIMA_LEFT:
    {
        start_ops = -lv_disp_get_hor_res(NULL);
        end_ops = 0;
        anima_cb = translateX_anima_cb;
    }
    break;
    default:
        break;
    }


    lv_anim_init(&appear_anima);
    lv_anim_set_user_data(&appear_anima, (void*)anima_data);
    lv_anim_set_var(&appear_anima, anima_data->pm_page->page);

    if (anima_data->pm_page->_back) {
        lv_anim_set_values(&appear_anima, start_ops, end_ops);
    }
    else {
        lv_anim_set_values(&appear_anima, -start_ops, -end_ops);
    }

    lv_anim_set_path_cb(&appear_anima, lv_anim_path_ease_out);
    lv_anim_set_time(&appear_anima, 500);
    lv_anim_set_repeat_count(&appear_anima, 1);
    lv_anim_set_exec_cb(&appear_anima, anima_cb);
    lv_anim_set_ready_cb(&appear_anima, anima_ready_cb);
    lv_anim_start(&appear_anima);
}

static void _pm_slide_disAppear(lv_pm_anima_data* anima_data)
{
    int32_t start_ops = 0;
    int32_t end_ops = 0;
    lv_anim_exec_xcb_t anima_cb = NULL;

    switch (anima_data->options.direction)
    {
    case LV_PM_ANIMA_TOP:
    {
        start_ops = lv_disp_get_ver_res(NULL);
        end_ops = 0;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_BOTTOM:
    {
        start_ops = -lv_disp_get_ver_res(NULL);
        end_ops = 0;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_RIGHT:
    {
        start_ops = lv_disp_get_hor_res(NULL);
        end_ops = 0;
        anima_cb = translateX_anima_cb;
    }
    break;
    case LV_PM_ANIMA_LEFT:
    {
        start_ops = -lv_disp_get_hor_res(NULL);
        end_ops = 0;
        anima_cb = translateX_anima_cb;
    }
    break;
    default:
        break;
    }

    lv_anim_init(&disAppear_anima);
    lv_anim_set_user_data(&disAppear_anima, (void*)anima_data);
    lv_anim_set_var(&disAppear_anima, anima_data->pm_page->page);

    if (anima_data->pm_page->_back) {
        lv_anim_set_values(&disAppear_anima, -end_ops, -start_ops);
    }
    else {
        lv_anim_set_values(&disAppear_anima, end_ops, start_ops);
    }

    lv_anim_set_time(&disAppear_anima, 500);
    lv_anim_set_repeat_count(&disAppear_anima, 1);
    lv_anim_set_exec_cb(&disAppear_anima, anima_cb);
    lv_anim_set_ready_cb(&disAppear_anima, anima_ready_cb);
    lv_anim_set_path_cb(&disAppear_anima, lv_anim_path_ease_out);
    lv_anim_start(&disAppear_anima);
}

/** ------------------------------------slide animation end-------------------------------------------- */


/**
----------------------------------------------------------------------------------------------------------
  popup animation弹入
----------------------------------------------------------------------------------------------------------
*/

static void _pm_popup_appear(lv_pm_anima_data* anima_data)
{
    int32_t start_ops1 = 0;
    int32_t end_ops1 = 0;
    int32_t start_ops2 = 0;
    int32_t end_ops2 = 0;
    lv_anim_exec_xcb_t anima_cb = NULL;

    switch (anima_data->options.direction)
    {
    case LV_PM_ANIMA_TOP:
    {
        start_ops1 = -lv_disp_get_ver_res(NULL);
        end_ops1 = 0;
        start_ops2 = lv_disp_get_ver_res(NULL) / 2;
        end_ops2 = 0;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_BOTTOM:
    {
        start_ops1 = lv_disp_get_ver_res(NULL);
        end_ops1 = 0;
        start_ops2 = lv_disp_get_ver_res(NULL) / 2;
        end_ops2 = 0;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_RIGHT:
    {
        start_ops1 = -lv_disp_get_hor_res(NULL);
        end_ops1 = 0;
        start_ops2 = -start_ops1 / 2;
        end_ops2 = 0;
        anima_cb = translateX_anima_cb;
    }
    break;
    case LV_PM_ANIMA_LEFT:
    {
        start_ops1 = lv_disp_get_hor_res(NULL);
        end_ops1 = 0;
        start_ops2 = -start_ops1 / 2;
        end_ops2 = 0;
        anima_cb = translateX_anima_cb;
    }
    break;
    default:
        break;
    }

    lv_anim_init(&appear_anima);
    lv_anim_set_user_data(&appear_anima, (void*)anima_data);
    lv_anim_set_var(&appear_anima, anima_data->pm_page->page);

    if (anima_data->pm_page->_back) {
        lv_anim_set_values(&appear_anima, start_ops2, end_ops2);
        //lv_obj_set_style_radius(anima_data->pm_page->page, 0, LV_STATE_DEFAULT);
    }
    else {
        lv_obj_move_foreground(anima_data->pm_page->page);/*打开时新界面从前方覆盖 否则动画可能会由于界面先后创建的问题导致异常*/
        lv_anim_set_values(&appear_anima, start_ops1, end_ops1);
        //lv_obj_set_style_radius(anima_data->pm_page->page, 10, LV_STATE_DEFAULT);
    }

    lv_anim_set_path_cb(&appear_anima, lv_anim_path_ease_out);
    lv_anim_set_time(&appear_anima, 500);
    lv_anim_set_repeat_count(&appear_anima, 1);
    lv_anim_set_exec_cb(&appear_anima, anima_cb);
    lv_anim_set_ready_cb(&appear_anima, anima_ready_cb);
    lv_anim_start(&appear_anima);
}

static void _pm_popup_disAppear(lv_pm_anima_data* anima_data)
{
    int32_t start_ops = 0;
    int32_t end_ops = 0;
    int32_t start_ops2 = 0;
    int32_t end_ops2 = 0;
    lv_anim_exec_xcb_t anima_cb = NULL;

    switch (anima_data->options.direction)
    {
    case LV_PM_ANIMA_TOP:
    {
        start_ops = 0;
        end_ops = -lv_disp_get_ver_res(NULL);
        start_ops2 = 0;
        end_ops2 = lv_disp_get_ver_res(NULL) / 2;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_BOTTOM:
    {
        start_ops = 0;
        end_ops = lv_disp_get_ver_res(NULL);
        start_ops2 = 0;
        end_ops2 = lv_disp_get_ver_res(NULL) / 2;
        anima_cb = translateY_anima_cb;
    }
    break;
    case LV_PM_ANIMA_RIGHT:
    {
        start_ops = 0;
        end_ops = -lv_disp_get_hor_res(NULL);
        start_ops2 = 0;
        end_ops2 = -end_ops / 2;
        anima_cb = translateX_anima_cb;
    }
    break;
    case LV_PM_ANIMA_LEFT:
    {
        start_ops = 0;
        end_ops = lv_disp_get_hor_res(NULL);
        start_ops2 = 0;
        end_ops2 = -end_ops / 2;
        anima_cb = translateX_anima_cb;
    }
    break;
    default:
        break;
    }

    lv_anim_init(&disAppear_anima);
    lv_anim_set_user_data(&disAppear_anima, (void*)anima_data);
    lv_anim_set_var(&disAppear_anima, anima_data->pm_page->page);

    if (anima_data->pm_page->_back) {
        lv_obj_move_foreground(anima_data->pm_page->page);/*退出时旧界面从前方覆盖 否则动画可能会由于界面先后创建的问题导致异常*/
        lv_anim_set_values(&disAppear_anima, start_ops, end_ops);
        //lv_obj_set_style_radius(anima_data->pm_page->page, 0, LV_STATE_DEFAULT);
    }
    else {
        lv_anim_set_values(&disAppear_anima, start_ops2, end_ops2);
        //lv_obj_set_style_radius(anima_data->pm_page->page, 10, LV_STATE_DEFAULT);
    }

    lv_anim_set_time(&disAppear_anima, 500);
    lv_anim_set_repeat_count(&disAppear_anima, 1);
    lv_anim_set_exec_cb(&disAppear_anima, anima_cb);
    lv_anim_set_ready_cb(&disAppear_anima, anima_ready_cb);
    lv_anim_set_path_cb(&disAppear_anima, lv_anim_path_ease_out);
    lv_anim_start(&disAppear_anima);
}

/** ------------------------------------popup animation end-------------------------------------------- */
/**
----------------------------------------------------------------------------------------------------------
  fade animation 淡入淡出
----------------------------------------------------------------------------------------------------------
*/

static void _pm_fade_timer_cb(lv_timer_t* tmr)
{
    lv_pm_anima_data* cb_data = (lv_pm_anima_data*)tmr->user_data;
    cb_data->cb(cb_data->pm_page, cb_data->options);
    lv_timer_pause(tmr);/*直接挂起定时器*/
    //printf("%s\r\n",__func__);
    //lv_timer_del(tmr);
}
static void _pm_fade_appear(lv_pm_anima_data* anima_data)
{
    lv_obj_fade_in(anima_data->pm_page->page, 1000, 500);/*淡入*/

    /*由于需要在淡出完全结束后才能调用cb进行释放内存的操作，这里就设定了定时器对页面被关闭的事件进行回调*/
    lv_timer_set_cb(lvgl_appear_timer, _pm_fade_timer_cb);
    lv_timer_reset(lvgl_appear_timer);/* 重置定时器运行的频率 */
    lv_timer_set_period(lvgl_appear_timer, 1500);
    lvgl_appear_timer->user_data = (void*)anima_data;
    lv_timer_resume(lvgl_appear_timer);/* 使定时器进入运行状态 */
}
static void _pm_fade_disAppear(lv_pm_anima_data* anima_data)
{
    lv_obj_fade_out(anima_data->pm_page->page, 1000, 0);/*淡出*/

    /*由于需要在淡出完全结束后才能调用cb进行释放内存的操作，这里就设定了定时器对页面被关闭的事件进行回调*/
    lv_timer_set_cb(lvgl_disAppear_timer, _pm_fade_timer_cb);
    lv_timer_reset(lvgl_disAppear_timer);/* 重置定时器运行的频率 */
    lv_timer_set_period(lvgl_disAppear_timer, 1500);
    lvgl_disAppear_timer->user_data = (void*)anima_data;
    lv_timer_resume(lvgl_disAppear_timer);/* 使定时器进入运行状态 */
}
/** ------------------------------------fade animation end-------------------------------------------- */
/* 进入动画回调处理 */
void _pm_anima_appear(lv_pm_page_t* pm_page, lv_pm_open_options_t* behavior, lv_pm_anima_complete_cb cb)
{
    if (behavior == NULL || behavior->animation == LV_PM_ANIMA_NONE) {
        cb(pm_page, *behavior);
        return;
    }
    static lv_pm_anima_data anima_data;/* 直接使用全局变量，防止内存泄露问题 */

    anima_data.pm_page = pm_page;
    anima_data.cb = cb;
    anima_data.options = *behavior;

    switch (behavior->animation)
    {
    case LV_PM_ANIMA_SLIDE:
        _pm_slide_appear(&anima_data);
        break;
    case LV_PM_ANIMA_POPUP:
        _pm_popup_appear(&anima_data);
        break;
    case LV_PM_ANIMA_FADE:
        _pm_fade_appear(&anima_data);
        break;
    default:
        cb(pm_page, *behavior);
        break;
    }
}
/* 退出动画回调处理 */
void _pm_anima_disAppear(lv_pm_page_t* pm_page, lv_pm_open_options_t* behavior, lv_pm_anima_complete_cb cb)
{
    if (behavior == NULL || behavior->animation == LV_PM_ANIMA_NONE) {
        cb(pm_page, *behavior);
        return;
    }

    static lv_pm_anima_data anima_data;/* 直接使用全局变量，防止内存泄露问题 */

    anima_data.pm_page = pm_page;
    anima_data.cb = cb;
    anima_data.options = *behavior;

    switch (behavior->animation)
    {
    case LV_PM_ANIMA_SLIDE:
        _pm_slide_disAppear(&anima_data);
        break;
    case LV_PM_ANIMA_POPUP:
        _pm_popup_disAppear(&anima_data);
        break;
    case LV_PM_ANIMA_FADE:
        _pm_fade_disAppear(&anima_data);
        break;
    default:
        cb(pm_page, *behavior);
        break;
    }
}
